extern "C" {
#include	<luajit.h>
#include	<lualib.h>
#include	<lauxlib.h>
}

#include	"../response.h"
#include	"../utils/logger.h"
#include	"../utils/utils.h"

extern std::string lua_tojson(lua_State *, int);

namespace LuaApi { namespace LuaResponse {
	static int Header(lua_State * pL) {
		Response * p = *(Response **)lua_topointer(pL, 1);
		const char * sK = lua_tostring(pL, 2);
		const char * sV = lua_tostring(pL, 3);
		p->Header(sK, sV);
		return 0;
	}

	static int Echo(lua_State * pL) {
		Response * p = *(Response **)lua_topointer(pL, 1);
		const char * s = lua_tostring(pL, 2);
		p->Echo(s);
		return 0;
	}

	static int Html(lua_State * pL) {
		int nTop = lua_gettop(pL);

		lua_getglobal(pL, "debug");
		lua_getfield(pL, -1, "traceback");
		lua_remove(pL, -2);

		lua_getglobal(pL, "template");
		lua_getfield(pL, -1, "render");
		lua_remove(pL, -2);

		lua_pushvalue(pL, 1);
		lua_pushvalue(pL, 2);
		if (nTop > 2) lua_pushvalue(pL, 3);
		if (nTop > 3) lua_pushvalue(pL, 4);

		if (lua_pcall(pL, nTop, 0, nTop + 1) != 0) {
			GLog.Error("Failed to compile html : %s", lua_tostring(pL, -1));
		}

		return 0;
	}

	static int Error(lua_State * pL) {
		Response * p = *(Response **)lua_topointer(pL, 1);
		int nCode = lua_tointeger(pL, 2);
		p->Error(nCode);
		return 0;
	}

	static int Redirect(lua_State * pL) {
		Response * p = *(Response **)lua_topointer(pL, 1);
		const char * s = lua_tostring(pL, 2);
		p->Redirect(s);
		return 0;
	}

	static int Cookie(lua_State * pL) {
		Response * p = *(Response **)lua_topointer(pL, 1);
		int nTop = lua_gettop(pL);

		std::string sHeader;
		sHeader.append(lua_tostring(pL, 2));
		sHeader.append("=");
		sHeader.append(lua_tostring(pL, 3));
		sHeader.append(";");

		if (nTop > 3) {
			sHeader.append("expires=");
			sHeader.append(GMTime((uint32_t)time(NULL) + (uint32_t)lua_tonumber(pL, 4)).c_str());
			sHeader.append(";");
		}

		if (nTop > 4) {
			sHeader.append("path=");
			sHeader.append(lua_tostring(pL, 5));
			sHeader.append(";");
		}

		p->Header("Set-cookie", sHeader);
		return 0;
	}

	static int Json(lua_State * pL) {
		Response * p = *(Response **)lua_topointer(pL, 1);
		p->Echo(lua_tojson(pL, 2));
		if (lua_gettop(pL) < 3 || lua_toboolean(pL, 3)) p->Header("Content-type", "application/json");		
		return 0;
	}

	static int Flush(lua_State * pL) {
		Response * p = *(Response **)lua_topointer(pL, 1);
		p->Send();
		return 0;
	}
} }

void RegisterApi_Response(lua_State * pL) {
	luaL_newmetatable(pL, "__omni_response");
	lua_pushvalue(pL, -1);
	lua_setfield(pL, -2, "__index");

	lua_pushcfunction(pL, &LuaApi::LuaResponse::Header);
	lua_setfield(pL, -2, "header");

	lua_pushcfunction(pL, &LuaApi::LuaResponse::Echo);
	lua_setfield(pL, -2, "echo");

	lua_pushcfunction(pL, &LuaApi::LuaResponse::Html);
	lua_setfield(pL, -2, "html");

	lua_pushcfunction(pL, &LuaApi::LuaResponse::Json);
	lua_setfield(pL, -2, "json");

	lua_pushcfunction(pL, &LuaApi::LuaResponse::Error);
	lua_setfield(pL, -2, "error");

	lua_pushcfunction(pL, &LuaApi::LuaResponse::Redirect);
	lua_setfield(pL, -2, "redirect");

	lua_pushcfunction(pL, &LuaApi::LuaResponse::Cookie);
	lua_setfield(pL, -2, "cookie");

	lua_pushcfunction(pL, &LuaApi::LuaResponse::Flush);
	lua_setfield(pL, -2, "flush");

	lua_pop(pL, 1);
}
